package com.gitee.wsl.compose.ui.textfield


import androidx.compose.foundation.border
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardCapitalization
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.unit.dp
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowDropDown
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.Search
import androidx.compose.material.icons.outlined.Visibility
import androidx.compose.material.icons.outlined.VisibilityOff
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.Text
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.Dp
import com.gitee.wsl.compose.ui.base.TextField
import com.gitee.wsl.compose.ui.textfield.TextFieldDefaults.applyBorder


/**
 * @author Vivien Mahe
 * @since 26/08/2023
 */

@Composable
fun TextField.FromField(
    text: String,
    modifier: Modifier = Modifier,
    label: String? = null,
    placeholderText: String? = null,
    size: TextFieldSize = TextFieldSize.REGULAR,
    type: TextFieldType = TextFieldType.TEXT,
    enabled: Boolean = true,
    singleLine: Boolean = false,
    imeAction: ImeAction = ImeAction.Default,
    capitalization: KeyboardCapitalization = KeyboardCapitalization.Sentences,
    keyboardActions: KeyboardActions = KeyboardActions.Default,
    onValueChanged: ((String) -> Unit)? = null,
) {
    var inputValue by remember { mutableStateOf(text) }
    var inputType by remember { mutableStateOf(type) }
    var hasFocus by remember { mutableStateOf(false) }
    var visualTransformation by remember { mutableStateOf(VisualTransformation.None) }

    LaunchedEffect(inputType) {
        visualTransformation = inputType.visualTransformation
    }

    val inputValueChanged: (String) -> Unit = {
        inputValue = it
        onValueChanged?.invoke(inputValue)
    }

    TextField(
        modifier = modifier
            .height(size.height)
            .onFocusChanged { focusState -> hasFocus = focusState.isFocused }
            .applyBorder(hasFocus = hasFocus, shape = size.shape),
        value = inputValue,
        placeholder = placeholderText?.let { { Text(it, style = size.textStyle) } },
        onValueChange = { inputValueChanged(it) },
        label = label?.let { { Text(it) } },
        enabled = enabled,
        textStyle = size.textStyle,
        singleLine = singleLine,
        visualTransformation = visualTransformation,
        keyboardOptions = inputType.keyboardOptions.copy(
            imeAction = imeAction,
            capitalization = capitalization,
        ),
        keyboardActions = keyboardActions,
        shape = size.shape,
        leadingIcon = inputType.leadingIcon?.let { { Icon(modifier = Modifier.size(size.iconSize), imageVector = it, contentDescription = null) } },
        trailingIcon = inputType.trailingIcon?.let {
            {
                IconButton(onClick = {
                    when (inputType) {
                        TextFieldType.PASSWORD_VISIBLE -> inputType = TextFieldType.PASSWORD_HIDDEN
                        TextFieldType.PASSWORD_HIDDEN -> inputType = TextFieldType.PASSWORD_VISIBLE
                        TextFieldType.SEARCH -> inputValueChanged("")
                        else -> Unit // Nothing to do for the other types
                    }
                }) {
                    Icon(modifier = Modifier.size(size.iconSize), imageVector = it, contentDescription = null)
                }
            }
        },
        colors = TextFieldDefaults.textFieldColors()
    )
}

@Composable
fun TextField.FromField(
    text: TextFieldValue,
    modifier: Modifier = Modifier,
    label: String? = null,
    placeholderText: String? = null,
    size: TextFieldSize = TextFieldSize.REGULAR,
    type: TextFieldType = TextFieldType.TEXT,
    enabled: Boolean = true,
    singleLine: Boolean = false,
    imeAction: ImeAction = ImeAction.Default,
    capitalization: KeyboardCapitalization = KeyboardCapitalization.Sentences,
    keyboardActions: KeyboardActions = KeyboardActions.Default,
    onValueChanged: ((TextFieldValue) -> Unit)? = null
) {
    var inputType by remember { mutableStateOf(type) }
    var hasFocus by remember { mutableStateOf(false) }
    var visualTransformation by remember { mutableStateOf(VisualTransformation.None) }

    LaunchedEffect(inputType) {
        visualTransformation = inputType.visualTransformation
    }

    TextField(
        modifier = modifier
            .height(size.height)
            .onFocusChanged { focusState -> hasFocus = focusState.isFocused }
            .applyBorder(hasFocus = hasFocus, shape = size.shape),
        value = text,
        placeholder = placeholderText?.let { { Text(it, style = size.textStyle) } },
        onValueChange = { if (text != it) onValueChanged?.invoke(it) },
        label = label?.let { { Text(it) } },
        enabled = enabled,
        textStyle = size.textStyle,
        singleLine = singleLine,
        visualTransformation = visualTransformation,
        keyboardOptions = inputType.keyboardOptions.copy(
            imeAction = imeAction,
            capitalization = capitalization,
        ),
        keyboardActions = keyboardActions,
        shape = size.shape,
        leadingIcon = inputType.leadingIcon?.let { { Icon(modifier = Modifier.size(size.iconSize), imageVector = it, contentDescription = null) } },
        trailingIcon = inputType.trailingIcon?.let {
            {
                IconButton(onClick = {
                    when (inputType) {
                        TextFieldType.PASSWORD_VISIBLE -> inputType = TextFieldType.PASSWORD_HIDDEN
                        TextFieldType.PASSWORD_HIDDEN -> inputType = TextFieldType.PASSWORD_VISIBLE
                        else -> Unit // Nothing to do for the other types
                    }
                }) {
                    Icon(modifier = Modifier.size(size.iconSize), imageVector = it, contentDescription = null)
                }
            }
        },
        colors = TextFieldDefaults.textFieldColors()
    )
}

private object TextFieldDefaults {

    @Composable
    fun Modifier.applyBorder(hasFocus: Boolean, shape: Shape = shape()) =
        this.border(
            width = if (hasFocus) 2.dp else 1.dp,
            color = if (hasFocus) MaterialTheme.colorScheme.inversePrimary else MaterialTheme.colorScheme.outlineVariant,
            shape = shape
        )

    @Composable
    fun shape() = MaterialTheme.shapes.extraLarge

    @Composable
    fun textFieldColors() = androidx.compose.material3.TextFieldDefaults.colors(
        focusedContainerColor = MaterialTheme.colorScheme.surface,
        unfocusedContainerColor = MaterialTheme.colorScheme.surface,
        disabledContainerColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = uiDisabledAlpha()),
        focusedTextColor = MaterialTheme.colorScheme.onBackground,
        unfocusedTextColor = MaterialTheme.colorScheme.onBackground,
        disabledTextColor = MaterialTheme.colorScheme.onBackground.copy(alpha = uiDisabledAlpha()),
        focusedLabelColor = MaterialTheme.colorScheme.outline,
        unfocusedLabelColor = MaterialTheme.colorScheme.outline,
        disabledLabelColor = MaterialTheme.colorScheme.onSurface.copy(alpha = uiDisabledAlpha()),
        focusedIndicatorColor = Color.Transparent,
        unfocusedIndicatorColor = Color.Transparent,
        disabledIndicatorColor = Color.Transparent,
        focusedPlaceholderColor = MaterialTheme.colorScheme.onBackground.copy(alpha = uiDisabledAlpha()),
        unfocusedPlaceholderColor = MaterialTheme.colorScheme.onBackground.copy(alpha = uiDisabledAlpha()),
        disabledPlaceholderColor = MaterialTheme.colorScheme.onBackground.copy(alpha = uiDisabledAlpha()),
    )
}

private fun uiDisabledAlpha(): Float = 0.38f

/**
 * @author Vivien Mahe
 * @since 04/04/2024
 */
enum class TextFieldSize {
    BIG,
    REGULAR,
    SMALL;

    companion object {
        private val BigTextFieldHeight = 84.dp
        private val TextFieldHeight = 52.dp
        private val SmallTextFieldHeight = 44.dp

        private val BigTextFieldIconSize = 44.dp
        private val TextFieldIconSize = 24.dp
        private val SmallTextFieldIconSize = 12.dp
    }

    val textStyle: TextStyle // Used for both text and placeholder
        @Composable
        @ReadOnlyComposable
        get() = when (this) {
            BIG -> MaterialTheme.typography.displayMedium
            REGULAR -> MaterialTheme.typography.titleMedium
            SMALL -> MaterialTheme.typography.labelMedium
        }

    val height: Dp
        @Composable
        @ReadOnlyComposable
        get() = when (this) {
            BIG -> BigTextFieldHeight
            REGULAR -> TextFieldHeight
            SMALL -> SmallTextFieldHeight
        }

    val shape: Shape
        @Composable
        @ReadOnlyComposable
        get() = when (this) {
            BIG -> CircleShape
            REGULAR -> MaterialTheme.shapes.extraLarge
            SMALL -> MaterialTheme.shapes.large
        }

    val iconSize: Dp
        @Composable
        @ReadOnlyComposable
        get() = when (this) {
            BIG -> BigTextFieldIconSize
            REGULAR -> TextFieldIconSize
            SMALL -> SmallTextFieldIconSize
        }
}


/**
 * @author Vivien Mahe
 * @since 26/08/2023
 */
enum class TextFieldType {
    TEXT,
    NUMBER,
    EMAIL,
    PASSWORD_VISIBLE,
    PASSWORD_HIDDEN,
    SEARCH,
    DROPDOWN;

    val leadingIcon: ImageVector?
        get() = when (this) {
            TEXT -> null
            NUMBER -> null
            EMAIL -> null
            PASSWORD_VISIBLE -> null
            PASSWORD_HIDDEN -> null
            SEARCH -> Icons.Default.Search
            DROPDOWN -> null
        }

    val trailingIcon: ImageVector?
        get() = when (this) {
            TEXT -> null
            NUMBER -> null
            EMAIL -> null
            PASSWORD_VISIBLE -> Icons.Outlined.VisibilityOff
            PASSWORD_HIDDEN -> Icons.Outlined.Visibility
            SEARCH -> Icons.Default.Close
            DROPDOWN -> Icons.Default.ArrowDropDown
        }

    val visualTransformation: VisualTransformation
        get() = when (this) {
            TEXT -> VisualTransformation.None
            NUMBER -> VisualTransformation.None
            EMAIL -> VisualTransformation.None
            PASSWORD_VISIBLE -> VisualTransformation.None
            PASSWORD_HIDDEN -> PasswordVisualTransformation()
            SEARCH -> VisualTransformation.None
            DROPDOWN -> VisualTransformation.None
        }

    val keyboardOptions: KeyboardOptions
        get() = when (this) {
            TEXT -> KeyboardOptions.Default
            NUMBER -> KeyboardOptions(keyboardType = KeyboardType.Number)
            EMAIL -> KeyboardOptions(keyboardType = KeyboardType.Email)
            PASSWORD_VISIBLE -> KeyboardOptions.Default
            PASSWORD_HIDDEN -> KeyboardOptions(keyboardType = KeyboardType.Password)
            SEARCH -> KeyboardOptions.Default
            DROPDOWN -> KeyboardOptions.Default
        }
}
